Frontend Forever App
We have a mobile app for you to download and use. And you can unlock many features in the app.
Get it now
Intall Later
Run
HTML
CSS
Javascript
Output
{{ currentTrack.artist }}
{{ currentTrack.name }}
{{ duration }}
{{ currentTime }}
See on GitHub
icon-heart-o
icon-heart
icon-infinity
icon-pause
icon-play
link
next
prev
@media only screen and (min-width: 768px) { #logo { width: 10%; } } body { background: #dfe7ef; font-family: "Bitter", serif; } * { box-sizing: border-box; } .icon { display: inline-block; width: 1em; height: 1em; stroke-width: 0; stroke: currentColor; fill: currentColor; } .wrapper { width: 100%; display: flex; align-items: center; justify-content: center; min-height: 100vh; background-size: cover; } @media screen and (max-width: 700px), (max-height: 500px) { .wrapper { flex-wrap: wrap; flex-direction: column; } } .player { background: #eef3f7; width: 410px; min-height: 480px; box-shadow: 0px 15px 35px -5px rgba(50, 88, 130, 0.32); border-radius: 15px; padding: 30px; } @media screen and (max-width: 576px), (max-height: 500px) { .player { width: 95%; padding: 20px; margin-top: 75px; min-height: initial; padding-bottom: 30px; max-width: 400px; } } .player__top { display: flex; align-items: flex-start; position: relative; z-index: 4; } @media screen and (max-width: 576px), (max-height: 500px) { .player__top { flex-wrap: wrap; } } .player-cover { width: 300px; height: 300px; margin-left: -70px; flex-shrink: 0; position: relative; z-index: 2; border-radius: 15px; z-index: 1; } @media screen and (max-width: 576px), (max-height: 500px) { .player-cover { margin-top: -70px; margin-bottom: 25px; width: 290px; height: 230px; margin-left: auto; margin-right: auto; } } .player-cover__item { background-repeat: no-repeat; background-position: center; background-size: cover; width: 100%; height: 100%; border-radius: 15px; position: absolute; left: 0; top: 0; } .player-cover__item:before { content: ""; background: inherit; width: 100%; height: 100%; box-shadow: 0px 10px 40px 0px rgba(76, 70, 124, 0.5); display: block; z-index: 1; position: absolute; top: 30px; transform: scale(0.9); filter: blur(10px); opacity: 0.9; border-radius: 15px; } .player-cover__item:after { content: ""; background: inherit; width: 100%; height: 100%; box-shadow: 0px 10px 40px 0px rgba(76, 70, 124, 0.5); display: block; z-index: 2; position: absolute; border-radius: 15px; } .player-cover__img { width: 100%; height: 100%; object-fit: cover; border-radius: 15px; box-shadow: 0px 10px 40px 0px rgba(76, 70, 124, 0.5); user-select: none; pointer-events: none; } .player-controls { flex: 1; padding-left: 20px; display: flex; flex-direction: column; align-items: center; } @media screen and (max-width: 576px), (max-height: 500px) { .player-controls { flex-direction: row; padding-left: 0; width: 100%; flex: unset; } } .player-controls__item { display: inline-flex; font-size: 30px; padding: 5px; margin-bottom: 10px; color: #acb8cc; cursor: pointer; width: 50px; height: 50px; align-items: center; justify-content: center; position: relative; transition: all 0.3s ease-in-out; } @media screen and (max-width: 576px), (max-height: 500px) { .player-controls__item { font-size: 26px; padding: 5px; margin-right: 10px; color: #acb8cc; cursor: pointer; width: 40px; height: 40px; margin-bottom: 0; } } .player-controls__item::before { content: ""; position: absolute; width: 100%; height: 100%; border-radius: 50%; background: #fff; transform: scale(0.5); opacity: 0; box-shadow: 0px 5px 10px 0px rgba(76, 70, 124, 0.2); transition: all 0.3s ease-in-out; transition: all 0.4s cubic-bezier(0.35, 0.57, 0.13, 0.88); } @media screen and (min-width: 500px) { .player-controls__item:hover { color: #532ab9; } .player-controls__item:hover::before { opacity: 1; transform: scale(1.3); } } @media screen and (max-width: 576px), (max-height: 500px) { .player-controls__item:active { color: #532ab9; } .player-controls__item:active::before { opacity: 1; transform: scale(1.3); } } .player-controls__item .icon { position: relative; z-index: 2; } .player-controls__item.-xl { margin-bottom: 0; font-size: 95px; filter: drop-shadow(0 11px 6px rgba(172, 184, 204, 0.45)); color: #fff; width: auto; height: auto; display: inline-flex; } @media screen and (max-width: 576px), (max-height: 500px) { .player-controls__item.-xl { margin-left: auto; font-size: 75px; margin-right: 0; } } .player-controls__item.-xl:before { display: none; } .player-controls__item.-favorite.active { color: red; } [v-cloak] { display: none; } [v-cloak] > * { display: none; } .progress { width: 100%; margin-top: -15px; user-select: none; } .progress__top { display: flex; align-items: flex-end; justify-content: space-between; } .progress__duration { color: #71829e; font-weight: 700; font-size: 20px; opacity: 0.5; } .progress__time { margin-top: 2px; color: #71829e; font-weight: 700; font-size: 16px; opacity: 0.7; } .progress__bar { height: 6px; width: 100%; cursor: pointer; background-color: #d0d8e6; display: inline-block; border-radius: 10px; } .progress__current { height: inherit; width: 0%; background-color: #a3b3ce; border-radius: 10px; } .album-info { color: #71829e; flex: 1; padding-right: 60px; user-select: none; } @media screen and (max-width: 576px), (max-height: 500px) { .album-info { padding-right: 30px; } } .album-info__name { font-size: 20px; font-weight: bold; margin-bottom: 12px; line-height: 1.3em; } @media screen and (max-width: 576px), (max-height: 500px) { .album-info__name { font-size: 18px; margin-bottom: 9px; } } .album-info__track { font-weight: 400; font-size: 20px; opacity: 0.7; line-height: 1.3em; min-height: 52px; } @media screen and (max-width: 576px), (max-height: 500px) { .album-info__track { font-size: 18px; min-height: 50px; } } .github-btn { position: absolute; right: 40px; bottom: 50px; text-decoration: none; padding: 15px 25px; border-radius: 4px; box-shadow: 0px 4px 30px -6px rgba(36, 52, 70, 0.65); background: #24292e; color: #fff; font-weight: bold; letter-spacing: 1px; font-size: 16px; transition: all 0.3s ease-in-out; } @media screen and (min-width: 500px) { .github-btn:hover { transform: scale(1.1); box-shadow: 0px 17px 20px -6px rgba(36, 52, 70, 0.36); } } @media screen and (max-width: 700px) { .github-btn { position: relative; bottom: auto; right: auto; margin-top: 20px; } .github-btn:active { transform: scale(1.1); box-shadow: 0px 17px 20px -6px rgba(36, 52, 70, 0.36); } } .scale-out-enter-active { transition: all 0.35s ease-in-out; } .scale-out-leave-active { transition: all 0.35s ease-in-out; } .scale-out-enter { transform: scale(0.55); pointer-events: none; opacity: 0; } .scale-out-leave-to { transform: scale(1.2); pointer-events: none; opacity: 0; } .scale-in-enter-active { transition: all 0.35s ease-in-out; } .scale-in-leave-active { transition: all 0.35s ease-in-out; } .scale-in-enter { transform: scale(1.2); pointer-events: none; opacity: 0; } .scale-in-leave-to { transform: scale(0.55); pointer-events: none; opacity: 0; } /*# sourceMappingURL=main.css.map */
new Vue({ el: "#app", data() { return { audio: null, circleLeft: null, barWidth: null, duration: null, currentTime: null, isTimerPlaying: false, tracks: [ { name: "Sun Sathiya ", artist: "Priya Saraiya, Divya Kumar", cover: "https://iili.io/HDjIDep.png", source: "https://audio.jukehost.co.uk/m9rKFdjU7Zy3j29TTv96fwSiFCLd4DJt", url: "https://www.youtube.com/watch?v=TGpG56pg3UU", favorited: false }, { name: "Kill This Love 💔", artist: "BlackPink", cover: "https://iili.io/H1hGdV2.jpg", source: "https://audio.jukehost.co.uk/XMq8hSwgPKbHkY4srMhPWEFqHSigxcNQ", url: "https://www.youtube.com/watch?v=2S24-y0Ij3Y&ab_channel=BLACKPINK", favorited: false }, { name: "DDU DU DDU DU 🔫 ", artist: "BlackPink", cover: "https://iili.io/H1hGJol.jpg", source: "https://audio.jukehost.co.uk/FamrE48qfWUNWmskzgBfiFW5mbaSUCG7", url: "https://www.youtube.com/watch?v=IHNzOHi8sJs&ab_channel=BLACKPINK", favorited: true }, { name: "Lovesick Girls", artist: "BlackPink", cover: "https://iili.io/H1hEyNf.jpg", source: "https://audio.jukehost.co.uk/kmMdEcT0mVFDBlkcf1ZoydqaM19deMJ1", url: "https://www.youtube.com/watch?v=dyRsYk0LyA8&ab_channel=BLACKPINK", favorited: false }, { name: "Playing With Fire 🔥", artist: "BlackPink", cover: "https://iili.io/H1hGFK7.jpg", source: "https://audio.jukehost.co.uk/9t8OuMg1bqsR0JtyADcqKaXbTaLvGOkl", url: "https://www.youtube.com/watch?v=9pdj4iJD08s&ab_channel=BLACKPINK", favorited: false }, { name: "As If It's Your Last", artist: "BlackPink", cover: "https://iili.io/H1hGKl9.jpg", source: "https://audio.jukehost.co.uk/cXSnf1QxAl4N7keT52hTID5wZC8Nmfu1", url: "https://www.youtube.com/watch?v=Amq-qlqbjYA&ab_channel=BLACKPINK", favorited: true }, { name: "Boy with Love", artist: "BTS", cover: "https://iili.io/H1hG2PS.jpg", source: "https://audio.jukehost.co.uk/k1H7J0lBSzjvK8pGe5pb3lPJeBCfcJUz", url: "https://www.youtube.com/watch?v=XsX3ATc3FbA&ab_channel=HYBELABELS", favorited: false }, { name: "Dynamite", artist: "BTS", cover: "https://iili.io/H1hGfSe.jpg", source: "https://audio.jukehost.co.uk/w5el9uHEuw5yFJ1dPjeP5lMO78BbtRdr", url: "https://www.youtube.com/watch?v=gdZLi9oWNZg&ab_channel=HYBELABELS", favorited: true }, { name: "DNA", artist: "BTS", cover: "https://iili.io/H1hGCAb.jpg", source: "https://audio.jukehost.co.uk/hhWaUJpcCrCCPi1S2wWup9uL1uVNjvOb", url: "https://www.youtube.com/watch?v=MBdVXkSdhwU&ab_channel=HYBELABELS", favorited: false }, { name: "Butter", artist: "BTS", cover: "https://iili.io/H1hGBHu.jpg", source: "https://audio.jukehost.co.uk/X2kcaQZROQIikDD5P65ZetiaqdrZNX77", url: "https://www.youtube.com/watch?v=WMweEpGlu_U&ab_channel=HYBELABELS", favorited: false } ], currentTrack: null, currentTrackIndex: 0, transitionName: null }; }, methods: { play() { if (this.audio.paused) { this.audio.play(); this.isTimerPlaying = true; } else { this.audio.pause(); this.isTimerPlaying = false; } }, generateTime() { let width = (100 / this.audio.duration) * this.audio.currentTime; this.barWidth = width + "%"; this.circleLeft = width + "%"; let durmin = Math.floor(this.audio.duration / 60); let dursec = Math.floor(this.audio.duration - durmin * 60); let curmin = Math.floor(this.audio.currentTime / 60); let cursec = Math.floor(this.audio.currentTime - curmin * 60); if (durmin < 10) { durmin = "0" + durmin; } if (dursec < 10) { dursec = "0" + dursec; } if (curmin < 10) { curmin = "0" + curmin; } if (cursec < 10) { cursec = "0" + cursec; } this.duration = durmin + ":" + dursec; this.currentTime = curmin + ":" + cursec; }, updateBar(x) { let progress = this.$refs.progress; let maxduration = this.audio.duration; let position = x - progress.offsetLeft; let percentage = (100 * position) / progress.offsetWidth; if (percentage > 100) { percentage = 100; } if (percentage < 0) { percentage = 0; } this.barWidth = percentage + "%"; this.circleLeft = percentage + "%"; this.audio.currentTime = (maxduration * percentage) / 100; this.audio.play(); }, clickProgress(e) { this.isTimerPlaying = true; this.audio.pause(); this.updateBar(e.pageX); }, prevTrack() { this.transitionName = "scale-in"; this.isShowCover = false; if (this.currentTrackIndex > 0) { this.currentTrackIndex--; } else { this.currentTrackIndex = this.tracks.length - 1; } this.currentTrack = this.tracks[this.currentTrackIndex]; this.resetPlayer(); }, nextTrack() { this.transitionName = "scale-out"; this.isShowCover = false; if (this.currentTrackIndex < this.tracks.length - 1) { this.currentTrackIndex++; } else { this.currentTrackIndex = 0; } this.currentTrack = this.tracks[this.currentTrackIndex]; this.resetPlayer(); }, resetPlayer() { this.barWidth = 0; this.circleLeft = 0; this.audio.currentTime = 0; this.audio.src = this.currentTrack.source; setTimeout(() => { if(this.isTimerPlaying) { this.audio.play(); } else { this.audio.pause(); } }, 300); }, favorite() { this.tracks[this.currentTrackIndex].favorited = !this.tracks[ this.currentTrackIndex ].favorited; } }, created() { let vm = this; this.currentTrack = this.tracks[0]; this.audio = new Audio(); this.audio.src = this.currentTrack.source; this.audio.ontimeupdate = function() { vm.generateTime(); }; this.audio.onloadedmetadata = function() { vm.generateTime(); }; this.audio.onended = function() { vm.nextTrack(); this.isTimerPlaying = true; }; // this is optional (for preload covers) for (let index = 0; index < this.tracks.length; index++) { const element = this.tracks[index]; let link = document.createElement('link'); link.rel = "prefetch"; link.href = element.cover; link.as = "image" document.head.appendChild(link) } } });